package ferp.android.managers;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.preference.PreferenceManager;
import ferp.android.BuildConfig;
import ferp.android.tasks.center.TaskGameReportSend;
import ferp.core.Version;
import ferp.core.game.Game;
import ferp.core.game.Settings;
import ferp.core.game.Statistics;
import ferp.core.log.Log;
import ferp.core.player.Profile;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * User: igorgok
 * Date: 9/12/12 12:03 PM
 */
public class ProfileManager
{
  // an arbitrary context can be passed here as we will get the application context and use it!
  public static ProfileManager instance(Context context)
  {
    if (instance == null)
      instance = new ProfileManager(context);

    return instance;
  }

  public Profile getCurrentProfile()
  {
    return selected == null ? setCurrentProfile() : selected;
  }

  public Version version() {return version;}

  public Profile setCurrentProfile()
  {
    // set the current profile if any
    int index = getProfileIndex(getLastProfileID());

    if (index == -1)
    {
      // profile not found, set to first available
      if (profiles.size() > 0)
        setCurrentProfile(0);
      else
        selected = null;
    }
    else
      selected = profiles.get(index);

    return selected;
  }

  public Profile setCurrentProfile(int index)
  {
    selected = profiles.get(index);

    setLastProfileID(selected.id);

    return selected;
  }

  public void reloadCurrentProfile()
  {
    try
    {
      selected = Profile.load(selected.getFileObject());
      profiles.set(getProfileIndex(selected.id), selected);
    }
    catch (Exception e)
    {
      Log.error(Log.TAG, e);
    }
  }

  public int getCurrentProfileIndex() {return profiles.indexOf(selected);}

  public Profile newCurrentProfile() throws Exception
  {
    // create new profile
    Profile p = new Profile();

    p.settings.locale = (selected == null ?  Settings.Locale.locale(Locale.getDefault().getLanguage()) : selected.settings.locale);
    p.settings.orientation = (selected == null ? getCurrentOrientation() : selected.settings.orientation);

    return (selected = p);
  }

  // returns true if at least one profile is configured for the cloud save
  public boolean hasAtLeastOneProfileWithCloudSaveOn()
  {
    for (Profile p : profiles)
      if (p.settings.cloudSave != Settings.CloudSave.NONE)
        return true;

    return false;
  }

  public Profile find(String id)
  {
    for (Profile p : profiles)
      if (p.id.equals(id))
        return p;

    return null;
  }

  private Settings.Orientation getCurrentOrientation()
  {
    return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? Settings.Orientation.LANDSCAPE : Settings.Orientation.PORTRAIT;
  }

  public List<Profile> getProfileList() {return profiles;}

  public int getProfileIndex(String id)
  {
    for (int i = 0; i < profiles.size(); ++i)
      if (profiles.get(i).id.equals(id))
        return i;

    return -1;
  }

  public void saveCurrentProfile(boolean deleteGame) throws Exception
  {
    if (deleteGame)
    {
      Statistics total = selected.getStatistics();
      Game g = selected.game();

      // update statistics
      if (g != null && g.statistics.sets.deals > 0)
      {
        total.update(g.statistics);
        total.games.deleted++;
      }

      selected.clearGame();
    }

    // save to file
    selected.save();
    // save last ID
    setLastProfileID(selected.id);

    // if it's new profile add it to the list
    if (profiles.indexOf(selected) == -1)
    {
      profiles.add(selected);
      // sort by nick name
      Collections.sort(profiles, SortByNickname.instance);
    }
  }

  public void deleteCurrentProfile(boolean deleteFromCloud)
  {
    deleteProfile(selected, deleteFromCloud);
  }

  public void deleteProfile(String nickname)
  {
    int index = 0;
    boolean found = false;

    while (index < profiles.size() && !found)
    {
      Profile p = profiles.get(index);

      if (p.nickname.equals(nickname))
        found = true;
      else
        index++;
    }

    if (found)
    {
      setCurrentProfile(index);
      deleteCurrentProfile(false);
    }
  }

  public void deleteProfile(Profile p, boolean deleteFromCloud)
  {
    // delete profile on cloud
    if (deleteFromCloud && p.settings.cloudSave != Settings.CloudSave.NONE)
      CloudManager.instance(context).delete(p.id);

    // delete local profile
    int index = profiles.indexOf(p);

    if (index != -1)
    {
      profiles.remove(index);
      p.delete();

      // set new current profile
      if (profiles.size() > 0)
      {
        if (selected == null || p == selected)
          setCurrentProfile(Math.min(index, profiles.size() - 1));
        else
          setCurrentProfile(profiles.indexOf(selected));
      }
      else
      {
        selected = null;
        removeLastProfileID();
      }
    }
  }

  public void addProfile(Profile p)
  {
    try
    {
      // once we have an old version of the loaded profile - remove it from the list
      // the contents will be replaced with the new one
      Profile existing = find(p.id);

      if (existing != null)
        profiles.remove(existing);

      p.save();
      profiles.add(p);
    }
    catch (IOException e)
    {
      Log.error(Log.TAG, e);
    }
  }

  // last profile ID key
  private static final String LAST_PROFILE_ID = "lastProfileID";

  // profile manager instance
  private static ProfileManager instance = null;

  // application context
  private final Context context;
  // list of loaded profiles
  private final ArrayList<Profile> profiles = new ArrayList<Profile>();
  // currently selected profile
  private Profile selected = null;
  // package info
  private final Version version = new Version();

  private static class SortByNickname implements Comparator<Profile>
  {
    public int compare(Profile p1, Profile p2)
    {
      return p1.nickname.compareTo(p2.nickname);
    }

    @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
    public boolean equals(Object o)
    {
      return this == o;
    }

    // comparator instance
    private static final SortByNickname instance = new SortByNickname();
  }

  private ProfileManager(Context context)
  {
    // ensure we use application context here
    this.context = context.getApplicationContext();

    // initialize app version data
    try
    {
      // get app version
      PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);

      version.name = pi.versionName;
      version.code = pi.versionCode;
    }
    catch (PackageManager.NameNotFoundException e)
    {
      version.name = "n/a";
      version.code = 0;
    }

    try
    {
      // initialize settings
      Settings.initialize(context.getFilesDir());

      // load stored profiles
      profiles.clear();

      // get file list
      File[] files = Settings.Folders.profiles.listFiles();

      if (files != null)
      {
        for (File f : files)
          try
          {
            // empty file has to be deleted silently
            if (f.length() == 0)
            {
              boolean b = f.delete();

              Log.debug(Log.TAG, "Empty file " + f.getName() + " has been deleted (" + b + ")");
            }
            else
            {
              // load individual profile
              Profile p = Profile.load(f);

              if (p != null && p.nickname != null)
                profiles.add(p);
              else
              {
                boolean b = BuildConfig.DEBUG || f.delete();

                error("p=" + p + ", nickname=" + (p == null ? null : p.nickname) + "\ndeleted=" + b);
              }
            }
          }
          catch (Exception e)
          {
            Log.error(Log.TAG, e);
            // delete corrupted file
            boolean b = BuildConfig.DEBUG || f.delete();

            error("exception: " + e.getClass().getName() + ", message: " + e.getMessage() + "\ndeleted=" + b);
          }

        // sort by nick name
        Collections.sort(profiles, SortByNickname.instance);
      }
      else
        Log.debug(Log.TAG, "file list is null");
    }
    catch (Settings.InitializationException e)
    {
      error(e.getMessage());
    }
  }

  private void error(String description) {new TaskGameReportSend(context, null, "load@profiles", description, null, null).execute();}

  private void setLastProfileID(String id)
  {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = preferences.edit();

    editor.putString(LAST_PROFILE_ID, id);
    editor.commit();
  }

  private String getLastProfileID() {return PreferenceManager.getDefaultSharedPreferences(context).getString(LAST_PROFILE_ID, "");}

  private void removeLastProfileID()
  {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = preferences.edit();

    editor.remove(LAST_PROFILE_ID);
    editor.commit();
  }
}
